package com.hxb.ruifeng.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.hxb.ruifeng.entity.enums.RedisKeyEnum;
import com.hxb.ruifeng.entity.vo.UserVo;
import com.hxb.ruifeng.util.DateUtils;
import com.hxb.ruifeng.util.JwtTokenUtil;
import com.hxb.ruifeng.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 基本滤波器
 * 请求拦截，避免服务绕过接口被直接访问
 *
 * @author 黄晓冰
 * @date 2024/01/07
 */
@Component
@WebFilter(filterName = "BaseFilter",urlPatterns = {"/**"})
@Order(999)
@Slf4j
public class BaseFilter implements Filter {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;


    /**
     * JWT 失效时间小于30分钟，更新JWT
     */
    private final static Long EXPIRED_JWT = 30 * 60L;

    /**
     * redis 30 分钟会话失效时间
     */
    private final static Long EXPIRED_REDIS = 30 * 60L;


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init filter");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("进入过滤器========");

        HttpServletResponse response = (HttpServletResponse) servletResponse;
        // 将ServletRequest强制转换为HttpServletRequest
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        // 返回JSON数据，设置响应内容类型为application/json
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");


        //获取请求的接口
        String path = request.getRequestURI();
        log.info("当前请求接口：" + path);

        //直接可请求的资源
        String[] ignoresUrl = {
                "login", "swagger-ui.html", "api-docs","ui","security",
                "swagger-resources","csrf"
        };

        //提取最后一个'/'的子串
        int index = path.lastIndexOf("/");
        path = path.substring(index + 1);

        for (String url : ignoresUrl) {
            //如果是直接可请求的资源
            if (path.contains(url)) {
                //放行
                filterChain.doFilter(request, response);
                return;
            }
        }
        //获取请求头
        String token = request.getHeader("X-Token");


        // 创建一个包含 code 和 message 的 Java 对象
        Map<String, Object> jsonResponse = new HashMap<>();
        //判断是否携带了密钥
        if(token == null || token.isEmpty()){
            //如果不携带密钥，返回401错误
            jsonResponse.put("code", 401);
            jsonResponse.put("message", "token为空");
            // 转换为 JSON 字符串
            ObjectMapper objectMapper = new ObjectMapper();
            String jsonData = objectMapper.writeValueAsString(jsonResponse);

            response.getWriter().write(jsonData);
        }else{
            //从缓存中获取jwt
            Object sessionJwt = redisUtil.get(RedisKeyEnum.REDIS_KEY_USER_INFO.getKey() + token);
            if (sessionJwt == null) {
                //如果为空，返回无效
                //如果不携带密钥，返回401错误
                jsonResponse.put("code", 401);
                jsonResponse.put("message", "token无效");
                // 转换为 JSON 字符串
                ObjectMapper objectMapper = new ObjectMapper();
                String jsonData = objectMapper.writeValueAsString(jsonResponse);
                response.getWriter().write(jsonData);
                return;
            }
            //将其转为字符串
            String authToken = String.valueOf(sessionJwt);
            //获取到用户信息
            String userInfo = jwtTokenUtil.getUsernameFromToken(authToken);

            //反序列化转为UserDto对象
            UserVo loginUser = new Gson().fromJson(userInfo, UserVo.class);
            //获取jwt失效时间
            Date getExpirationDateFromToken = jwtTokenUtil.getExpirationDateFromToken(String.valueOf(sessionJwt));
            long remainingMinutes = DateUtils.getMinuteDifference(getExpirationDateFromToken, DateUtils.getCurrentTime());

            //如果小于半小时，刷新JWT
            if (remainingMinutes <= EXPIRED_JWT) {
                // randomKey和token已经生成完毕
                final String randomKey = jwtTokenUtil.getRandomKey();
                final String newToken = jwtTokenUtil.generateToken(userInfo, randomKey);

                //保存新的token
                redisUtil.set(RedisKeyEnum.REDIS_KEY_USER_INFO.getKey() + loginUser.getToken(),
                        newToken,
                        RedisKeyEnum.REDIS_KEY_USER_INFO.getExpireTime());
            }
            //小于半小时刷新Redis时间
            long expireTime = redisUtil.getExpire(RedisKeyEnum.REDIS_KEY_USER_INFO.getKey() + loginUser.getToken());
            if (expireTime <= EXPIRED_REDIS) {
                //刷新redis时间
                redisUtil.expire(RedisKeyEnum.REDIS_KEY_USER_INFO.getKey() + loginUser.getToken(),
                        RedisKeyEnum.REDIS_KEY_USER_INFO.getExpireTime());
            }
            //放行
            filterChain.doFilter(request, response);
        }
    }

    @Override
    public void destroy() {
        System.out.println("destroy filter");
    }

}